# Copyright (c) 2025 胡伯融
# 视频截图 is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan
# PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#          http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# **导入：对于被导入代码包，执行代码包中的__init__.py文件的代码内容。对于被导入文件，执行代码内容中的__main__段落之外的代码内容。
# **特别名字：包括位于英文字母名字开头和结尾的两根下划线的名字。写入蟒蛇解释器内部，无需自主声明的名字。
# **__name__：存储量。字符串。
# **__main__：字符串。执行蟒蛇解释器的运行文件的命令的场景中，被访问文件的标记。
import os
# 导入os。
from PIL import Image
# 类/Image图像。
# 1.导入PIL。 2.声明Image。
from moviepy import VideoFileClip
# 类/VideoFileClip视频文件剪辑。
# 1.导入moviepy。 2.声明VideoFileClip。


# *时间点：字符串，小时:分钟:秒格式，秒允许整数或小数。
# *图片大小：元组/两项整数元素，分别表示宽和长。
# ***帧：数组，对于视频，表示视频中的单张图片。
# **对象：所有被操作的单项数据的通用名称。
# **容器：类，保存一批对象为主要用途。
# **迭代：面向有限数目元素的或无限数目元素的容器逐个访问元素。
# **迭代器：又称可迭代对象，允许被迭代。
# **map映射类型：迭代器。每次迭代，对于创建映射数据结构输入的可迭代对象中的元素，应用创建映射数据结构输入的函数。
# **map映射函数：输入函数和可迭代对象，返回映射的数据结构。
# **字符串类split切分函数：输入字符串，输出列表/字符串。效果是字符串切分被切分字符串。
# **float浮点函数：转换整数成为小数或者转换字符串的字面数值成为小数。
# **解包：拆分单项多元素对象成为数目匹配的多项对象。
# **乘法：*符号，效果是计算两数的乘积。
# **加法：+符号，效果是计算两数的和。
# **算数顺序：乘除先于加减。
# **关键字参数：调用位置书写参数名字，用于传递参数对应的根据。
# **切片：选中元素序列中的部分元素，返回被选中的元素。
# **os.path.basename基本名字函数：输入路径，输出字符串，效果是返回路径目标的包括后缀的名字。
# **字符串类join拼接函数：输入字符串和列表/字符串，输出字符串，效果是拼接路径的组成部分。
# **字符串类format格式函数：输入包含{}的格式字符串，数目匹配格式字符串中{}数目的语句，输出字符串，效果是格式字符串中{}被替换成为语句的包含数据结构的值。
# **os.path.join拼接函数：输入路径，输出路径，效果是拼接路径。
# **os.path.dirname文件夹名字函数：输入路径，输出路径，效果是返回路径目标的所在文件夹的路径。
# +函数/save_timepoint_screenshot保存时间点截图。
# -字符串/param_video_file_path参数视频文件路径。
# -字符串/param_screenshot_folder_path参数截屏文件夹路径。
# -字符串/param_timepoint参数时间点。
# -元组/整数/param_picture_size参数图片形状。
# -小数/param_rotation_angle参数旋转角度。
# -返回None无的数据结构。
def save_timepoint_screenshot(param_video_file_path: os.PathLike, param_screenshot_folder_path: os.PathLike, param_timepoint: str, param_picture_size: tuple[int]=None, param_rotation_angle: float=None) -> None:
    # ：计算秒单位的时间目标。
    hour, minute, second = map(float, param_timepoint.split(':'))
    # 小数/hours小时。小数/minutes分钟。小数/seconds秒。
    # 1.调用[str].split，取得英文冒号字符切分param_timepoint字符串列表。 
    # 2.调用map，输入float函数和步骤1字符串列表，返回map类型。 3.迭代映射。
    # 4.解包步骤3返回数据，赋值hour,minute,second。
    time_target = hour * 3600 + minute * 60 + second
    # 小数/time_target时间目标。
    # 1.小时乘3600，分钟乘60，秒三项求和，效果是计算秒单位的时间。 2.赋值time_target。
    
    # ：获取视频帧。
    video = VideoFileClip(param_video_file_path)
    # VideoFileClip视频文件修剪/video视频。
    # 1.输入param_video_path参数视频路径，返回VideoFileClip视频文件修剪实例。 2.赋值video视频。
    frame = video.get_frame(time_target)
    # 数组/frame帧。
    # 1.调用VideoFileClip视频文件修剪的类get_frame返回帧的函数，输入时间目标，返回帧。 2.赋值frame帧。
    video.close()
    # 效果是解除视频占用。
    
    # ：转换图像。
    image = Image.fromarray(frame)
    # Image图像/image图像。
    # 1.调用Image图像的类fromarray来自数组的函数，输入帧，输出Image图像的实例。 2.赋值image图像。
    if param_picture_size is not None:
    # 验证param_picture_size参数图片大小的非无。
        image = image.resize(param_picture_size)
        # 1.调用Image图像的类resize改变大小的函数。输入param_picture_size参数图片大小。效果是变更图片长宽大小。 2.赋值image图像。
    if param_rotation_angle is not None:
    # 验证param_rotation_angle旋转角度的非无。
        image = image.rotate(param_rotation_angle, expand=True)
        # 1.调用Image图像的类rotate旋转的函数。输入param_rotation_angle参数旋转角度，expand延展关键字参数True真值。效果是图片旋转角度变更，放大图片适配长宽大小。2.赋值image图像。

    # ：计算图像名字。
    picture_name = '.'.join(os.path.basename(param_video_file_path).split('.')[:-1])
    # 字符串/picture_name图像名字。
    # 1.调用os操作系统的包basename基本名字的函数，返回字符串。 2.调用字符串的类split切分的函数，返回列表/字符串。 3.调用列表的类切片，返回列表/字符串。 4.调用字符串的类join拼接的函数，返回路径。 
    
    # ：计算图像路径。
    picture_path = os.path.join(param_screenshot_folder_path, f"{picture_name}_{''.join(param_timepoint.split(':'))}.png")
    # 路径/picture_path图像路径。
    # 1.调用字符串类split切分的函数，返回列表/字符串。 2.调用字符串类join拼接的函数，返回字符串。 3.调用字符串类format格式的函数，返回字符串。 4.调用os操作系统的包join合并的函数，返回路径。
    
    # ：存储图片。
    image.save(picture_path)
    # 调用[Image].save，效果是存储图片。


if __name__ == "__main__":
    data_path = os.path.join(os.path.dirname(__file__), "data")
    # 路径/data_path数据路径。
    # 1.调用os.path.dirname，返回路径。 2.调用os.path.join，返回路径。 3.赋值data_path。

    # ：保存视频截图。
    video_path = os.path.join(data_path, "video.mp4")
    # 路径/video_path视频文件路径。
    # 1.调用os.path.join，返回路径。 2.赋值video_path。
    screenshot_folder_path = data_path
    # 路径/screenshot_folder_path视频截图文件夹路径。
    # 赋值screenshot_folder_path。
    timepoint = "00:00:01.0"
    # 字符串/timepoint时间点。
    # 赋值timepoint。
    save_timepoint_screenshot(video_path, screenshot_folder_path, timepoint)
    # 调用save_timepoint_screenshot，输入video_path，screenshot_folder_path，timepoint。  
